.set				noreorder
.set				noat

.equ				TRAINER_OFFSET, 0x00400000
.equ				INJECTOR_OFFSET, 0x00402000

;ROM
;.org				0xB1FFDC00
;RAM
;.org				0x80000000 + INJECTOR_OFFSET

;	JAL at [RA - 0x30]
;	Stack:
;	RA at [SP + 0x24]
;	S3 through S0 stored at [SP + 0x20] through [SP + 0x14]

SW	RA,	%lo(0xFFFC)	(SP)	;

LUI	S0,	%hi(0x80000000 + INJECTOR_OFFSET + Loader_Stub)		;
ORI	S0,	S0,	%lo(0x80000000 + INJECTOR_OFFSET + Loader_Stub)	;
LUI	S1,	0x8007		;
ORI	S1,	S1,	0x50C4	;Where the loader stub goes
ORI	S2,	R0,	%lo(End_Loader_Stub - Loader_Stub)	;S2 == Size - 4

				Inject_Loop:
LW	S3,	0x0000	(S0)	;
LW	RA,	0x0000	(S1)	;
BNEL	S3,	RA,		Inject_Write
SW	S3,	0x0000	(S1)	;
				Inject_Write:
ADDIU	S0,	S0,	0x0004	;
ADDIU	S1,	S1,	0x0004	;
BNEZL	S2,			Inject_Loop
ADDIU	S2,	S2,	-0x0004	;

LW	RA,	%lo(0xFFFC)	(SP)	;
ADDIU	RA,	RA,	-0x0030	;Address of JAL; this must unfortunately must be a magic number
LW	S0,	0x0000	(RA)	;
LUI	S1,	%hi(0x80000000 + INJECTOR_OFFSET + Incorrect_JAL)		;
LW	S2,	%lo(0x80000000 + INJECTOR_OFFSET + Incorrect_JAL)	(S1)	;
BNEL	S0,	S2,		Inject_JAL_Write
SW	S0,	%lo(0x80000000 + INJECTOR_OFFSET + Incorrect_JAL)	(S1)	;
				Inject_JAL_Write:

;	Why do I have to do this?

LUI	S0,	0x8040		;
SW	SP,	0x1FFC	(S0)	;

;	Just in case

LW	RA,	0x0024	(SP)	;
LW	S0,	0x0014	(SP)	;
LW	S1,	0x0018	(SP)	;
LW	S2,	0x001C	(SP)	;
LW	S3,	0x0020	(SP)	;

;	Replaced instructions

LH	T6,	0x0000	(A0)	;
ADDIU	AT,	R0,	0x4231	;
OR	S1,	A0,	R0	;
BNE	T6,	AT,		Sim_1f43980
OR	S3,	A1,	R0	;
LH	T7,	0x0002	(A0)	;
OR	S2,	R0,	R0	;
BLEZ	T7,			Sim_1f43980
OR	S0,	A0,	R0	;
				Sim_1f43950:
LW	T8,	0x0004	(S0)	;
OR	A1,	S1,	R0	;
ADDU	A0,	T8,	S1	;
BEQ	A0,	R0,		Sim_1f4396c
SW	A0,	0x0004	(S0)	;

;	Why do I have to do this?

LUI	SP,	0x8040		;
LW	SP,	0x1FFC	(SP)	;

				Incorrect_JAL:
JAL				0x000000C4
OR	A2,	S3,	R0	;

;	Why do I have to do this?

LUI	SP,	0x8040		;
LW	SP,	0x1FFC	(SP)	;

				Sim_1f4396c:
LH	T0,	0x0002	(S1)	;
ADDIU	S2,	S2,	0x0001	;
SLT	AT,	S2,	T0	;
BNEZ	AT,			Sim_1f43950
ADDIU	S0,	S0,	0x0004	;
				Sim_1f43980:
LW	RA,	0x0024	(SP)	;
LW	S0,	0x0014	(SP)	;
LW	S1,	0x0018	(SP)	;
LW	S2,	0x001C	(SP)	;
LW	S3,	0x0020	(SP)	;
JR	RA			;
ADDIU	SP,	SP,	0x0028	;

;	Loader stub

				Loader_Stub:
;.org				0x800750C4
LUI	V1,	%hi(0x80000000 + TRAINER_OFFSET)		;
LW	V0,	%lo(0x7FFFFFFC + TRAINER_OFFSET)	(V1)	;
LUI	A0,	0xC0DE		;
BEQ	V0,	A0,		Execute
NOP
LUI	V0,		0xB1FF	;mips-elf-as hack; should be 0xB200
ORI	V0,	V0,	0xE000	;mips-elf-as hack; should be unnecessary
ORI	A0,	R0,	0x1FF8	;
				Load_Loop:
LD	A2,	0x0000	(V0)	;mips-elf-as hack; should be able to use 0xE000 as offset
ADDIU	V0,	V0,	0x0008	;
SD	A2,	%lo(0x80000000 + TRAINER_OFFSET)	(V1)	;
ADDIU	V1,	V1,	0x0008	;
BGTZL	A0,			Load_Loop
ADDIU	A0,	A0,	-0x0008	;((0x1FF8 + 0x8)/0x8) iterations * 8 bytes per iteration = 8 kb copied
				Execute:
				End_Loader_Stub:
J				TRAINER_OFFSET
